package common.utils;

import java.lang.reflect.Array;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.collections.MapUtils;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

public class HttpUtils {

  public static String getRealIp(HttpServletRequest request) {
    return (request.getHeader("X-Real-IP") != null) ? request
        .getHeader("X-Real-IP") : request.getRemoteAddr();
  }

  public static Hashtable parseQueryString(String s) {
    String[] valArray = null;
    if (s == null) {
      throw new IllegalArgumentException("queryString must not null");
    }
    Hashtable ht = new Hashtable();
    StringBuffer sb = new StringBuffer();
    StringTokenizer st = new StringTokenizer(s, "&");
    while (st.hasMoreTokens()) {
      String pair = st.nextToken();
      if (pair.trim().length() != 0) {
        int pos = pair.indexOf('=');
        if (pos == -1) {
          throw new IllegalArgumentException(
              "cannot parse queryString:" + s);
        }
        String key = parseName(pair.substring(0, pos), sb);
        String val = parseName(pair.substring(pos + 1, pair.length()),
            sb);
        if (ht.containsKey(key)) {
          String[] oldVals = (String[]) ht.get(key);
          valArray = new String[oldVals.length + 1];
          for (int i = 0; i < oldVals.length; i++) {
            valArray[i] = oldVals[i];
          }
          valArray[oldVals.length] = val;
        } else {
          valArray = new String[1];
          valArray[0] = val;
        }
        ht.put(key, valArray);
      }
    }
    return fixValueArray2SingleStringObject(ht);
  }

  private static Hashtable fixValueArray2SingleStringObject(Hashtable ht) {
    Hashtable result = new Hashtable();
    for (Iterator it = ht.entrySet().iterator(); it.hasNext(); ) {
      Map.Entry entry = (Map.Entry) it.next();
      String[] valueArray = (String[]) entry.getValue();
      if (valueArray == null) {
        result.put(entry.getKey(), valueArray);
      } else {
        result.put(entry.getKey(),
            valueArray.length == 1 ? valueArray[0] : valueArray);
      }
    }
    return result;
  }

  private static String parseName(String s, StringBuffer sb) {
    sb.setLength(0);
    for (int i = 0; i < s.length(); i++) {
      char c = s.charAt(i);
      switch (c) {
        case '+':
          sb.append(' ');
          break;
        case '%':
          try {
            sb.append((char) Integer.parseInt(
                s.substring(i + 1, i + 3), 16));

            i += 2;
          } catch (NumberFormatException e) {
            throw new IllegalArgumentException();
          } catch (StringIndexOutOfBoundsException e) {
            String rest = s.substring(i);
            sb.append(rest);
            if (rest.length() == 2) {
              i++;
            }
          }

        default:
          sb.append(c);
      }
    }
    return sb.toString();
  }

  public static String getQueryString(Map<String, String[]> params) {
    if (params == null || params.size() == 0) {
      return "";
    }
    StringBuilder sb = new StringBuilder();
    for (Iterator it = params.entrySet().iterator(); it.hasNext(); ) {
      Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) it
          .next();
      String[] values = entry.getValue();

      if (values.length == 0) {
        continue;
      }

      if (values.length == 1) {
        sb.append(entry.getKey()).append("=").append(values[0]);
      } else {
        for (int i = 0; i < values.length; i++) {
          sb.append(entry.getKey()).append("=").append(values[i]);
          if (i < values.length - 1) {
            sb.append("&");
          }
        }
      }

      sb.append("&");
    }

    if (sb.length() > 0) {
      return sb.toString().substring(0, sb.length() - 1);
    }
    return sb.toString();
  }

  public static String getQueryStringByMapObject(Map<String, Object> params) {
    if (params == null || params.size() == 0) {
      return "";
    }
    StringBuilder sb = new StringBuilder();
    for (Iterator it = params.entrySet().iterator(); it.hasNext(); ) {
      Map.Entry<String, String[]> entry = (Map.Entry<String, String[]>) it
          .next();
      Object values = entry.getValue();
      if (values.getClass().isArray()) {
        int length = Array.getLength(values);

        if (length == 0) {
          continue;
        }

        if (length == 1) {
          sb.append(entry.getKey()).append("=").append(Array.get(values, 0));
        } else {
          for (int i = 0; i < length; i++) {
            sb.append(entry.getKey()).append("=").append(Array.get(values, i));
            if (i < length - 1) {
              sb.append("&");
            }
          }
        }

      } else {
        sb.append(entry.getKey()).append("=").append(values);
      }
      sb.append("&");
    }

    if (sb.length() > 0) {
      return sb.toString().substring(0, sb.length() - 1);
    }
    return sb.toString();
  }

  public static String getHostIp() {
    InetAddress inetAddress = getInetAddress();
    if (inetAddress == null) {
      return null;
    }
    String ip = inetAddress.getHostAddress();
    return ip;
  }

  public static String getHostName() {
    InetAddress inetAddress = getInetAddress();
    if (inetAddress == null) {
      return null;
    }
    String name = inetAddress.getHostName();
    return name;
  }

  private static InetAddress getInetAddress() {
    InetAddress inetAddress = null;
    try {
      inetAddress = InetAddress.getLocalHost();
    } catch (UnknownHostException e) {
      e.printStackTrace();
    }
    return inetAddress;
  }

  public static List<NameValuePair> getByMap(Map<String, String> params) {
    List<NameValuePair> nvps = new ArrayList<NameValuePair>(params.size());
    for (String key : params.keySet()) {
      String value = params.get(key);
      if (value == null) {
        value = "";
      }
      nvps.add(new BasicNameValuePair(key, value));
    }
    return nvps;
  }

  public static String getStringByMap(Map<String, String> params) {
    if (MapUtils.isNotEmpty(params)) {
      StringBuffer stringBuffer = new StringBuffer();
      for (String key : params.keySet()) {
        String value = params.get(key);
        if (Objects.isNull(value)) {
          value = "";
        }
        stringBuffer.append(key).append("=").append(value).append("&");
      }
      return stringBuffer.deleteCharAt(stringBuffer.length() - 1).toString();
    }
    return "";
  }
}
